   /*******************************************************/
   /*      "C" Language Integrated Production System      */
   /*                                                     */
   /*             CLIPS Version 6.24  05/17/06            */
   /*                                                     */
   /*            MISCELLANEOUS FUNCTIONS MODULE           */
   /*******************************************************/

/*************************************************************/
/* Purpose:                                                  */
/*                                                           */
/* Principal Programmer(s):                                  */
/*      Gary D. Riley                                        */
/*                                                           */
/* Contributing Programmer(s):                               */
/*      Brian L. Dantes                                      */
/*                                                           */
/* Revision History:                                         */
/*      6.23: Correction for FalseSymbol/TrueSymbol. DR0859  */
/*                                                           */
/*            Corrected compilation errors for files         */
/*            generated by constructs-to-c. DR0861           */
/*                                                           */
/*            Changed name of variable exp to theExp         */
/*            because of Unix compiler warnings of shadowed  */
/*            definitions.                                   */
/*                                                           */
/*      6.24: Removed CONFLICT_RESOLUTION_STRATEGIES,        */
/*            DYNAMIC_SALIENCE, INCREMENTAL_RESET,           */
/*            LOGICAL_DEPENDENCIES, IMPERATIVE_METHODS       */
/*            INSTANCE_PATTERN_MATCHING,                     */
/*            IMPERATIVE_MESSAGE_HANDLERS, and               */
/*            AUXILIARY_MESSAGE_HANDLERS compilation flags.  */
/*                                                           */
/*            Renamed BOOLEAN macro type to intBool.         */
/*                                                           */
/*************************************************************/

#define _MISCFUN_SOURCE_

#include <stdio.h>
#define _STDIO_INCLUDED_
#include <string.h>

#include "setup.h"

#include "argacces.h"
#include "envrnmnt.h"
#include "exprnpsr.h"
#include "memalloc.h"
#include "multifld.h"
#include "router.h"
#include "sysdep.h"
#include "utility.h"

#if DEFFUNCTION_CONSTRUCT
#include "dffnxfun.h"
#endif

#include "miscfun.h"

#define MISCFUN_DATA 9

struct miscFunctionData
  { 
   long long GensymNumber;
  };

#define MiscFunctionData(theEnv,execStatus) ((struct miscFunctionData *) GetEnvironmentData(theEnv,execStatus,MISCFUN_DATA))

/***************************************/
/* LOCAL INTERNAL FUNCTION DEFINITIONS */
/***************************************/

   static void                    ExpandFuncMultifield(void *,EXEC_STATUS,DATA_OBJECT *,EXPRESSION *,
                                                       EXPRESSION **,void *);
   static int                     FindLanguageType(void *,EXEC_STATUS,char *);
   
/*****************************************************************/
/* MiscFunctionDefinitions: Initializes miscellaneous functions. */
/*****************************************************************/
globle void MiscFunctionDefinitions(
  void *theEnv,
  EXEC_STATUS)
  {
   AllocateEnvironmentData(theEnv,execStatus,MISCFUN_DATA,sizeof(struct miscFunctionData),NULL);
   MiscFunctionData(theEnv,execStatus)->GensymNumber = 1;
   
#if ! RUN_TIME
   EnvDefineFunction2(theEnv,execStatus,"gensym",           'w', PTIEF GensymFunction,      "GensymFunction", "00");
   EnvDefineFunction2(theEnv,execStatus,"gensym*",          'w', PTIEF GensymStarFunction,  "GensymStarFunction", "00");
   EnvDefineFunction2(theEnv,execStatus,"setgen",           'g', PTIEF SetgenFunction,      "SetgenFunction", "11i");
   EnvDefineFunction2(theEnv,execStatus,"system",           'v', PTIEF gensystem,           "gensystem", "1*k");
   EnvDefineFunction2(theEnv,execStatus,"length",           'g', PTIEF LengthFunction,      "LengthFunction", "11q");
   EnvDefineFunction2(theEnv,execStatus,"length$",          'g', PTIEF LengthFunction,      "LengthFunction", "11q");
   EnvDefineFunction2(theEnv,execStatus,"time",             'd', PTIEF TimeFunction,        "TimeFunction", "00");
   EnvDefineFunction2(theEnv,execStatus,"random",           'g', PTIEF RandomFunction,      "RandomFunction", "02i");
   EnvDefineFunction2(theEnv,execStatus,"seed",             'v', PTIEF SeedFunction,        "SeedFunction", "11i");
   EnvDefineFunction2(theEnv,execStatus,"conserve-mem",     'v', PTIEF ConserveMemCommand,  "ConserveMemCommand", "11w");
   EnvDefineFunction2(theEnv,execStatus,"release-mem",      'g', PTIEF ReleaseMemCommand,   "ReleaseMemCommand", "00");
#if DEBUGGING_FUNCTIONS
   EnvDefineFunction2(theEnv,execStatus,"mem-used",         'g', PTIEF MemUsedCommand,      "MemUsedCommand", "00");
   EnvDefineFunction2(theEnv,execStatus,"mem-requests",     'g', PTIEF MemRequestsCommand,  "MemRequestsCommand", "00");
#endif
   EnvDefineFunction2(theEnv,execStatus,"options",          'v', PTIEF OptionsCommand,      "OptionsCommand", "00");
   EnvDefineFunction2(theEnv,execStatus,"operating-system", 'w', PTIEF OperatingSystemFunction,"OperatingSystemFunction", "00");
   EnvDefineFunction2(theEnv,execStatus,"(expansion-call)", 'u', PTIEF ExpandFuncCall,      "ExpandFuncCall",NULL);
   EnvDefineFunction2(theEnv,execStatus,"expand$",'u', PTIEF DummyExpandFuncMultifield,
                                           "DummyExpandFuncMultifield","11m");
   FuncSeqOvlFlags(theEnv,execStatus,"expand$",FALSE,FALSE);
   EnvDefineFunction2(theEnv,execStatus,"(set-evaluation-error)",
                                       'w', PTIEF CauseEvaluationError,"CauseEvaluationError",NULL);
   EnvDefineFunction2(theEnv,execStatus,"set-sequence-operator-recognition",
                                       'b', PTIEF SetSORCommand,"SetSORCommand","11w");
   EnvDefineFunction2(theEnv,execStatus,"get-sequence-operator-recognition",'b',
                    PTIEF EnvGetSequenceOperatorRecognition,"EnvGetSequenceOperatorRecognition","00");
   EnvDefineFunction2(theEnv,execStatus,"get-function-restrictions",'s',
                   PTIEF GetFunctionRestrictions,"GetFunctionRestrictions","11w");
   EnvDefineFunction2(theEnv,execStatus,"create$",     'm', PTIEF CreateFunction,  "CreateFunction", NULL);
   EnvDefineFunction2(theEnv,execStatus,"mv-append",   'm', PTIEF CreateFunction,  "CreateFunction", NULL);
   EnvDefineFunction2(theEnv,execStatus,"apropos",   'v', PTIEF AproposCommand,  "AproposCommand", "11w");
   EnvDefineFunction2(theEnv,execStatus,"get-function-list",   'm', PTIEF GetFunctionListFunction,  "GetFunctionListFunction", "00");
   EnvDefineFunction2(theEnv,execStatus,"funcall",'u', PTIEF FuncallFunction,"FuncallFunction","1**k");
   EnvDefineFunction2(theEnv,execStatus,"new",'u', PTIEF NewFunction,"NewFunction","1*uw");
   EnvDefineFunction2(theEnv,execStatus,"call",'u', PTIEF CallFunction,"CallFunction","1*u");
   EnvDefineFunction2(theEnv,execStatus,"timer",'d', PTIEF TimerFunction,"TimerFunction","**");
#endif
  }

/******************************************************************/
/* CreateFunction: H/L access routine for the create$ function.   */
/******************************************************************/
globle void CreateFunction(
  void *theEnv,
  EXEC_STATUS,
  DATA_OBJECT_PTR returnValue)
  {
   StoreInMultifield(theEnv,execStatus,returnValue,GetFirstArgument(),TRUE);
  }

/*****************************************************************/
/* SetgenFunction: H/L access routine for the setgen function.   */
/*****************************************************************/
globle long long SetgenFunction(
  void *theEnv,
  EXEC_STATUS)
  {
   long long theLong;
   DATA_OBJECT theValue;

   /*==========================================================*/
   /* Check to see that a single integer argument is provided. */
   /*==========================================================*/

   if (EnvArgCountCheck(theEnv,execStatus,"setgen",EXACTLY,1) == -1) return(MiscFunctionData(theEnv,execStatus)->GensymNumber);
   if (EnvArgTypeCheck(theEnv,execStatus,"setgen",1,INTEGER,&theValue) == FALSE) return(MiscFunctionData(theEnv,execStatus)->GensymNumber);

   /*========================================*/
   /* The integer must be greater than zero. */
   /*========================================*/

   theLong = ValueToLong(theValue.value);

   if (theLong < 1LL)
     {
      ExpectedTypeError1(theEnv,execStatus,"setgen",1,"number (greater than or equal to 1)");
      return(MiscFunctionData(theEnv,execStatus)->GensymNumber);
     }

   /*====================================*/
   /* Set the gensym index to the number */
   /* provided and return this value.    */
   /*====================================*/

   MiscFunctionData(theEnv,execStatus)->GensymNumber = theLong;
   return(theLong);
  }

/****************************************/
/* GensymFunction: H/L access routine   */
/*   for the gensym function.           */
/****************************************/
globle void *GensymFunction(
  void *theEnv,
  EXEC_STATUS)
  {
   char genstring[128];
   
   /*===========================================*/
   /* The gensym function accepts no arguments. */
   /*===========================================*/

   EnvArgCountCheck(theEnv,execStatus,"gensym",EXACTLY,0);

   /*================================================*/
   /* Create a symbol using the current gensym index */
   /* as the postfix.                                */
   /*================================================*/

   gensprintf(genstring,"gen%lld",MiscFunctionData(theEnv,execStatus)->GensymNumber);
   MiscFunctionData(theEnv,execStatus)->GensymNumber++;

   /*====================*/
   /* Return the symbol. */
   /*====================*/

   return(EnvAddSymbol(theEnv,execStatus,genstring));
  }

/************************************************/
/* GensymStarFunction: H/L access routine for   */
/*   the gensym* function.                      */
/************************************************/
globle void *GensymStarFunction(
  void *theEnv,
  EXEC_STATUS)
  {
   /*============================================*/
   /* The gensym* function accepts no arguments. */
   /*============================================*/

   EnvArgCountCheck(theEnv,execStatus,"gensym*",EXACTLY,0);

   /*====================*/
   /* Return the symbol. */
   /*====================*/

   return(GensymStar(theEnv,execStatus));
  }

/************************************/
/* GensymStar: C access routine for */
/*   the gensym* function.          */
/************************************/
globle void *GensymStar(
  void *theEnv,
  EXEC_STATUS)
  {
   char genstring[128];
   
   /*=======================================================*/
   /* Create a symbol using the current gensym index as the */
   /* postfix. If the symbol is already present in the      */
   /* symbol table, then continue generating symbols until  */
   /* a unique symbol is found.                             */
   /*=======================================================*/

   do
     {
      gensprintf(genstring,"gen%lld",MiscFunctionData(theEnv,execStatus)->GensymNumber);
      MiscFunctionData(theEnv,execStatus)->GensymNumber++;
     }
   while (FindSymbolHN(theEnv,execStatus,genstring) != NULL);

   /*====================*/
   /* Return the symbol. */
   /*====================*/

   return(EnvAddSymbol(theEnv,execStatus,genstring));
  }

/********************************************/
/* RandomFunction: H/L access routine for   */
/*   the random function.                   */
/********************************************/
globle long long RandomFunction(
  void *theEnv,
  EXEC_STATUS)
  {
   int argCount;
   long long rv;
   DATA_OBJECT theValue;
   long long begin, end;

   /*====================================*/
   /* The random function accepts either */
   /* zero or two arguments.             */
   /*====================================*/

   argCount = EnvRtnArgCount(theEnv,execStatus);
   
   if ((argCount != 0) && (argCount != 2))
     {
      PrintErrorID(theEnv,execStatus,"MISCFUN",2,FALSE);
      EnvPrintRouter(theEnv,execStatus,WERROR,"Function random expected either 0 or 2 arguments\n"); 
     }

   /*========================================*/
   /* Return the randomly generated integer. */
   /*========================================*/

   rv = genrand();
   
   if (argCount == 2)
     {
      if (EnvArgTypeCheck(theEnv,execStatus,"random",1,INTEGER,&theValue) == FALSE) return(rv);
      begin = DOToLong(theValue);
      if (EnvArgTypeCheck(theEnv,execStatus,"random",2,INTEGER,&theValue) == FALSE) return(rv);
      end = DOToLong(theValue);
      if (end < begin)
        {
         PrintErrorID(theEnv,execStatus,"MISCFUN",3,FALSE);
         EnvPrintRouter(theEnv,execStatus,WERROR,"Function random expected argument #1 to be less than argument #2\n"); 
         return(rv);
        }
        
      rv = begin + (rv % ((end - begin) + 1));
     }
   
   
   return(rv);
  }

/******************************************/
/* SeedFunction: H/L access routine for   */
/*   the seed function.                   */
/******************************************/
globle void SeedFunction(
  void *theEnv,
  EXEC_STATUS)
  {
   DATA_OBJECT theValue;

   /*==========================================================*/
   /* Check to see that a single integer argument is provided. */
   /*==========================================================*/

   if (EnvArgCountCheck(theEnv,execStatus,"seed",EXACTLY,1) == -1) return;
   if (EnvArgTypeCheck(theEnv,execStatus,"seed",1,INTEGER,&theValue) == FALSE) return;

   /*=============================================================*/
   /* Seed the random number generator with the provided integer. */
   /*=============================================================*/

   genseed((int) DOToLong(theValue));
  }

/********************************************/
/* LengthFunction: H/L access routine for   */
/*   the length$ function.                  */
/********************************************/
globle long long LengthFunction(
  void *theEnv,
  EXEC_STATUS)
  {
   DATA_OBJECT item;

   /*====================================================*/
   /* The length$ function expects exactly one argument. */
   /*====================================================*/

   if (EnvArgCountCheck(theEnv,execStatus,"length$",EXACTLY,1) == -1) return(-1L);
   EnvRtnUnknown(theEnv,execStatus,1,&item);

   /*====================================================*/
   /* If the argument is a string or symbol, then return */
   /* the number of characters in the argument.          */
   /*====================================================*/

   if ((GetType(item) == STRING) || (GetType(item) == SYMBOL))
     {  return( (long) strlen(DOToString(item))); }

   /*====================================================*/
   /* If the argument is a multifield value, then return */
   /* the number of fields in the argument.              */
   /*====================================================*/

   if (GetType(item) == MULTIFIELD)
     { return ( (long) GetDOLength(item)); }

   /*=============================================*/
   /* If the argument wasn't a string, symbol, or */
   /* multifield value, then generate an error.   */
   /*=============================================*/

   SetEvaluationError(theEnv,execStatus,TRUE);
   ExpectedTypeError2(theEnv,execStatus,"length$",1);
   return(-1L);
  }

/*******************************************/
/* ReleaseMemCommand: H/L access routine   */
/*   for the release-mem function.         */
/*******************************************/
globle long long ReleaseMemCommand(
  void *theEnv,
  EXEC_STATUS)
  {
   /*================================================*/
   /* The release-mem function accepts no arguments. */
   /*================================================*/

   if (EnvArgCountCheck(theEnv,execStatus,"release-mem",EXACTLY,0) == -1) return(0LL);

   /*========================================*/
   /* Release memory to the operating system */
   /* and return the amount of memory freed. */
   /*========================================*/

   return(EnvReleaseMem(theEnv,execStatus,-1L,FALSE));
  }

/******************************************/
/* ConserveMemCommand: H/L access routine */
/*   for the conserve-mem command.        */
/******************************************/
globle void ConserveMemCommand(
  void *theEnv,
  EXEC_STATUS)
  {
   char *argument;
   DATA_OBJECT theValue;

   /*===================================*/
   /* The conserve-mem function expects */
   /* a single symbol argument.         */
   /*===================================*/

   if (EnvArgCountCheck(theEnv,execStatus,"conserve-mem",EXACTLY,1) == -1) return;
   if (EnvArgTypeCheck(theEnv,execStatus,"conserve-mem",1,SYMBOL,&theValue) == FALSE) return;

   argument = DOToString(theValue);

   /*====================================================*/
   /* If the argument is the symbol "on", then store the */
   /* pretty print representation of a construct when it */
   /* is defined.                                        */
   /*====================================================*/

   if (strcmp(argument,"on") == 0)
     { EnvSetConserveMemory(theEnv,execStatus,TRUE); }

   /*======================================================*/
   /* Otherwise, if the argument is the symbol "off", then */
   /* don't store the pretty print representation of a     */
   /* construct when it is defined.                        */
   /*======================================================*/

   else if (strcmp(argument,"off") == 0)
     { EnvSetConserveMemory(theEnv,execStatus,FALSE); }

   /*=====================================================*/
   /* Otherwise, generate an error since the only allowed */
   /* arguments are "on" or "off."                        */
   /*=====================================================*/

   else
     {
      ExpectedTypeError1(theEnv,execStatus,"conserve-mem",1,"symbol with value on or off");
      return;
     }

   return;
  }

#if DEBUGGING_FUNCTIONS

/****************************************/
/* MemUsedCommand: H/L access routine   */
/*   for the mem-used command.          */
/****************************************/
globle long long MemUsedCommand(
  void *theEnv,
  EXEC_STATUS)
  {
   /*=============================================*/
   /* The mem-used function accepts no arguments. */
   /*=============================================*/

   if (EnvArgCountCheck(theEnv,execStatus,"mem-used",EXACTLY,0) == -1) return(0);

   /*============================================*/
   /* Return the amount of memory currently held */
   /* (both for current use and for later use).  */
   /*============================================*/

   return(EnvMemUsed(theEnv,execStatus));
  }

/********************************************/
/* MemRequestsCommand: H/L access routine   */
/*   for the mem-requests command.          */
/********************************************/
globle long long MemRequestsCommand(
  void *theEnv,
  EXEC_STATUS)
  {
   /*=================================================*/
   /* The mem-requests function accepts no arguments. */
   /*=================================================*/

   if (EnvArgCountCheck(theEnv,execStatus,"mem-requests",EXACTLY,0) == -1) return(0);

   /*==================================*/
   /* Return the number of outstanding */
   /* memory requests.                 */
   /*==================================*/

   return(EnvMemRequests(theEnv,execStatus));
  }

#endif

/****************************************/
/* AproposCommand: H/L access routine   */
/*   for the apropos command.           */
/****************************************/
globle void AproposCommand(
  void *theEnv,
  EXEC_STATUS)
  {
   char *argument;
   DATA_OBJECT argPtr;
   struct symbolHashNode *hashPtr = NULL;
   size_t theLength;

   /*=======================================================*/
   /* The apropos command expects a single symbol argument. */
   /*=======================================================*/

   if (EnvArgCountCheck(theEnv,execStatus,"apropos",EXACTLY,1) == -1) return;
   if (EnvArgTypeCheck(theEnv,execStatus,"apropos",1,SYMBOL,&argPtr) == FALSE) return;

   /*=======================================*/
   /* Determine the length of the argument. */
   /*=======================================*/

   argument = DOToString(argPtr);
   theLength = strlen(argument);

   /*====================================================================*/
   /* Print each entry in the symbol table that contains the argument as */
   /* a substring. When using a non-ANSI compiler, only those strings    */
   /* that contain the substring starting at the beginning of the string */
   /* are printed.                                                       */
   /*====================================================================*/

   while ((hashPtr = GetNextSymbolMatch(theEnv,execStatus,argument,theLength,hashPtr,TRUE,NULL)) != NULL)
     {
      EnvPrintRouter(theEnv,execStatus,WDISPLAY,ValueToString(hashPtr));
      EnvPrintRouter(theEnv,execStatus,WDISPLAY,"\n");
     }
  }

/****************************************/
/* OptionsCommand: H/L access routine   */
/*   for the options command.           */
/****************************************/
globle void OptionsCommand(
  void *theEnv,
  EXEC_STATUS)
  {
   /*===========================================*/
   /* The options command accepts no arguments. */
   /*===========================================*/

   if (EnvArgCountCheck(theEnv,execStatus,"options",EXACTLY,0) == -1) return;

   /*=================================*/
   /* Print the state of the compiler */
   /* flags for this executable.      */
   /*=================================*/

   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Machine type: ");

#if GENERIC
   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Generic ");
#endif
#if VAX_VMS
   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"VAX VMS ");
#endif
#if UNIX_V
   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"UNIX System V or 4.2BSD ");
#endif
#if DARWIN
   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Darwin ");
#endif
#if LINUX
   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Linux ");
#endif
#if UNIX_7
   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"UNIX System III Version 7 or Sun Unix ");
#endif
#if MAC_MCW
   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Apple Macintosh with CodeWarrior");
#endif
#if MAC_XCD
   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Apple Macintosh with Xcode");
#endif
#if WIN_MVC
   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Microsoft Windows with Microsoft Visual C++");
#endif
#if WIN_BTC
   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Microsoft Windows with Borland Turbo C++");
#endif
#if WIN_MCW
   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Microsoft Windows with Metrowerks CodeWarrior");
#endif
#if WIN_GCC
   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Microsoft Windows with DJGPP");
#endif
EnvPrintRouter(theEnv,execStatus,WDISPLAY,"\n");

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Defrule construct is ");
#if DEFRULE_CONSTRUCT
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Defmodule construct is ");
#if DEFMODULE_CONSTRUCT
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Deftemplate construct is ");
#if DEFTEMPLATE_CONSTRUCT
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"  Fact-set queries are ");
#if FACT_SET_QUERIES
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

#if DEFTEMPLATE_CONSTRUCT

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"  Deffacts construct is ");
#if DEFFACTS_CONSTRUCT
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Defglobal construct is ");
#if DEFGLOBAL_CONSTRUCT
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Deffunction construct is ");
#if DEFFUNCTION_CONSTRUCT
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Defgeneric/Defmethod constructs are ");
#if DEFGENERIC_CONSTRUCT
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Object System is ");
#if OBJECT_SYSTEM
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

#if OBJECT_SYSTEM

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"  Definstances construct is ");
#if DEFINSTANCES_CONSTRUCT
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"  Instance-set queries are ");
#if INSTANCE_SET_QUERIES
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"  Binary loading of instances is ");
#if BLOAD_INSTANCES
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"  Binary saving of instances is ");
#if BSAVE_INSTANCES
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Extended math function package is ");
#if EXTENDED_MATH_FUNCTIONS
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Text processing function package is ");
#if TEXTPRO_FUNCTIONS
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Help system is ");
#if HELP_FUNCTIONS
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Bload capability is ");
#if BLOAD_ONLY
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"BLOAD ONLY");
#endif
#if BLOAD
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"BLOAD");
#endif
#if BLOAD_AND_BSAVE
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"BLOAD AND BSAVE");
#endif
#if (! BLOAD_ONLY) && (! BLOAD) && (! BLOAD_AND_BSAVE)
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF ");
#endif
EnvPrintRouter(theEnv,execStatus,WDISPLAY,"\n");

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"EMACS Editor is ");
#if EMACS_EDITOR
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Construct compiler is ");
#if CONSTRUCT_COMPILER
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"I/O function package is ");
#if IO_FUNCTIONS
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"String function package is ");
#if STRING_FUNCTIONS
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Multifield function package is ");
#if MULTIFIELD_FUNCTIONS
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Debugging function package is ");
#if DEBUGGING_FUNCTIONS
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Block memory is ");
#if BLOCK_MEMORY
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Window Interface flag is ");
#if WINDOW_INTERFACE
   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Developer flag is ");
#if DEVELOPER
   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
   EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif

EnvPrintRouter(theEnv,execStatus,WDISPLAY,"Run time module is ");
#if RUN_TIME
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"ON\n");
#else
  EnvPrintRouter(theEnv,execStatus,WDISPLAY,"OFF\n");
#endif
  }

/***********************************************/
/* OperatingSystemFunction: H/L access routine */
/*   for the operating system function.        */
/***********************************************/
globle void *OperatingSystemFunction(
  void *theEnv,
  EXEC_STATUS)
  {
   EnvArgCountCheck(theEnv,execStatus,"operating-system",EXACTLY,0);

#if GENERIC
   return(EnvAddSymbol(theEnv,execStatus,"UNKNOWN"));
#endif

#if VAX_VMS
   return(EnvAddSymbol(theEnv,execStatus,"VMS"));
#endif

#if UNIX_V
   return(EnvAddSymbol(theEnv,execStatus,"UNIX-V"));
#endif

#if UNIX_7
   return(EnvAddSymbol(theEnv,execStatus,"UNIX-7"));
#endif

#if LINUX
   return(EnvAddSymbol(theEnv,execStatus,"LINUX"));
#endif

#if DARWIN
   return(EnvAddSymbol(theEnv,execStatus,"DARWIN"));
#endif

#if MAC_XCD || MAC_MCW
   return(EnvAddSymbol(theEnv,execStatus,"MAC-OS-X"));
#endif

#if IBM && (! WINDOW_INTERFACE)
   return(EnvAddSymbol(theEnv,execStatus,"DOS"));
#endif

#if IBM && WINDOW_INTERFACE
   return(EnvAddSymbol(theEnv,execStatus,"WINDOWS"));
#endif

   return(EnvAddSymbol(theEnv,execStatus,"UNKNOWN"));
  }
  
/********************************************************************
  NAME         : ExpandFuncCall
  DESCRIPTION  : This function is a wrap-around for a normal
                   function call.  It preexamines the argument
                   expression list and expands any references to the
                   sequence operator.  It builds a copy of the
                   function call expression with these new arguments
                   inserted and evaluates the function call.
  INPUTS       : A data object buffer
  RETURNS      : Nothing useful
  SIDE EFFECTS : Expressions alloctaed/deallocated
                 Function called and arguments evaluated
                 EvaluationError set on errors
  NOTES        : None
 *******************************************************************/
globle void ExpandFuncCall(
  void *theEnv,
  EXEC_STATUS,
  DATA_OBJECT *result)
  {
   EXPRESSION *newargexp,*fcallexp;
   struct FunctionDefinition *func;

   /* ======================================================================
      Copy the original function call's argument expression list.
      Look for expand$ function callsexpressions and replace those
        with the equivalent expressions of the expansions of evaluations
        of the arguments.
      ====================================================================== */
   newargexp = CopyExpression(theEnv,execStatus,GetFirstArgument()->argList);
   ExpandFuncMultifield(theEnv,execStatus,result,newargexp,&newargexp,
                        (void *) FindFunction(theEnv,execStatus,"expand$"));

   /* ===================================================================
      Build the new function call expression with the expanded arguments.
      Check the number of arguments, if necessary, and call the thing.
      =================================================================== */
   fcallexp = get_struct(theEnv,execStatus,expr);
   fcallexp->type = GetFirstArgument()->type;
   fcallexp->value = GetFirstArgument()->value;
   fcallexp->nextArg = NULL;
   fcallexp->argList = newargexp;
   if (fcallexp->type == FCALL)
     {
      func = (struct FunctionDefinition *) fcallexp->value;
      if (CheckFunctionArgCount(theEnv,execStatus,ValueToString(func->callFunctionName),
                                func->restrictions,CountArguments(newargexp)) == FALSE)
        {
         result->type = SYMBOL;
         result->value = EnvFalseSymbol(theEnv,execStatus);
         ReturnExpression(theEnv,execStatus,fcallexp);
         return;
        }
     }
#if DEFFUNCTION_CONSTRUCT
   else if (fcallexp->type == PCALL)
     {
      if (CheckDeffunctionCall(theEnv,execStatus,fcallexp->value,
              CountArguments(fcallexp->argList)) == FALSE)
        {
         result->type = SYMBOL;
         result->value = EnvFalseSymbol(theEnv,execStatus);
         ReturnExpression(theEnv,execStatus,fcallexp);
         SetEvaluationError(theEnv,execStatus,TRUE);
         return;
        }
     }
#endif

   EvaluateExpression(theEnv,execStatus,fcallexp,result);
   ReturnExpression(theEnv,execStatus,fcallexp);
  }

/***********************************************************************
  NAME         : DummyExpandFuncMultifield
  DESCRIPTION  : The expansion of multifield arguments is valid only
                 when done for a function call.  All these expansions
                 are handled by the H/L wrap-around function
                 (expansion-call) - see ExpandFuncCall.  If the H/L
                 function, epand-multifield is ever called directly,
                 it is an error.
  INPUTS       : Data object buffer
  RETURNS      : Nothing useful
  SIDE EFFECTS : EvaluationError set
  NOTES        : None
 **********************************************************************/
globle void DummyExpandFuncMultifield(
  void *theEnv,
  EXEC_STATUS,
  DATA_OBJECT *result)
  {
   result->type = SYMBOL;
   result->value = EnvFalseSymbol(theEnv,execStatus);
   SetEvaluationError(theEnv,execStatus,TRUE);
   PrintErrorID(theEnv,execStatus,"MISCFUN",1,FALSE);
   EnvPrintRouter(theEnv,execStatus,WERROR,"expand$ must be used in the argument list of a function call.\n");
  }

/***********************************************************************
  NAME         : ExpandFuncMultifield
  DESCRIPTION  : Recursively examines an expression and replaces
                   PROC_EXPAND_MULTIFIELD expressions with the expanded
                   evaluation expression of its argument
  INPUTS       : 1) A data object result buffer
                 2) The expression to modify
                 3) The address of the expression, in case it is
                    deleted entirely
                 4) The address of the H/L function expand$
  RETURNS      : Nothing useful
  SIDE EFFECTS : Expressions allocated/deallocated as necessary
                 Evaluations performed
                 On errors, argument expression set to call a function
                   which causes an evaluation error when evaluated
                   a second time by actual caller.
  NOTES        : THIS ROUTINE MODIFIES EXPRESSIONS AT RUNTIME!!  MAKE
                 SURE THAT THE EXPRESSION PASSED IS SAFE TO CHANGE!!
 **********************************************************************/
static void ExpandFuncMultifield(
  void *theEnv,
  EXEC_STATUS,
  DATA_OBJECT *result,
  EXPRESSION *theExp,
  EXPRESSION **sto,
  void *expmult)
  {
   EXPRESSION *newexp,*top,*bot;
   register long i; /* 6.04 Bug Fix */

   while (theExp != NULL)
     {
      if (theExp->value == expmult)
        {
         EvaluateExpression(theEnv,execStatus,theExp->argList,result);
         ReturnExpression(theEnv,execStatus,theExp->argList);
         if ((execStatus->EvaluationError) || (result->type != MULTIFIELD))
           {
            theExp->argList = NULL;
            if ((execStatus->EvaluationError == FALSE) && (result->type != MULTIFIELD))
              ExpectedTypeError2(theEnv,execStatus,"expand$",1);
            theExp->value = (void *) FindFunction(theEnv,execStatus,"(set-evaluation-error)");
            execStatus->EvaluationError = FALSE;
            execStatus->HaltExecution = FALSE;
            return;
           }
         top = bot = NULL;
         for (i = GetpDOBegin(result) ; i <= GetpDOEnd(result) ; i++)
           {
            newexp = get_struct(theEnv,execStatus,expr);
            newexp->type = GetMFType(result->value,i);
            newexp->value = GetMFValue(result->value,i);
            newexp->argList = NULL;
            newexp->nextArg = NULL;
            if (top == NULL)
              top = newexp;
            else
              bot->nextArg = newexp;
            bot = newexp;
           }
         if (top == NULL)
           {
            *sto = theExp->nextArg;
            rtn_struct(theEnv,execStatus,expr,theExp);
            theExp = *sto;
           }
         else
           {
            bot->nextArg = theExp->nextArg;
            *sto = top;
            rtn_struct(theEnv,execStatus,expr,theExp);
            sto = &bot->nextArg;
            theExp = bot->nextArg;
           }
        }
      else
        {
         if (theExp->argList != NULL)
           ExpandFuncMultifield(theEnv,execStatus,result,theExp->argList,&theExp->argList,expmult);
         sto = &theExp->nextArg;
         theExp = theExp->nextArg;
        }
     }
  }

/****************************************************************
  NAME         : CauseEvaluationError
  DESCRIPTION  : Dummy function use to cause evaluation errors on
                   a function call to generate error messages
  INPUTS       : None
  RETURNS      : A pointer to the FalseSymbol
  SIDE EFFECTS : EvaluationError set
  NOTES        : None
 ****************************************************************/
globle void *CauseEvaluationError(
  void *theEnv,
  EXEC_STATUS)
  {
   SetEvaluationError(theEnv,execStatus,TRUE);
   return((SYMBOL_HN *) EnvFalseSymbol(theEnv,execStatus));
  }

/****************************************************************
  NAME         : SetSORCommand
  DESCRIPTION  : Toggles SequenceOpMode - if TRUE, multifield
                   references are replaced with sequence
                   expansion operators
  INPUTS       : None
  RETURNS      : The old value of SequenceOpMode
  SIDE EFFECTS : SequenceOpMode toggled
  NOTES        : None
 ****************************************************************/
globle intBool SetSORCommand(
  void *theEnv,
  EXEC_STATUS)
  {
#if (! RUN_TIME) && (! BLOAD_ONLY)
   DATA_OBJECT arg;

   if (EnvArgTypeCheck(theEnv,execStatus,"set-sequence-operator-recognition",1,SYMBOL,&arg) == FALSE)
     return(ExpressionData(theEnv,execStatus)->SequenceOpMode);
   return(EnvSetSequenceOperatorRecognition(theEnv,execStatus,(arg.value == EnvFalseSymbol(theEnv,execStatus)) ?
                                         FALSE : TRUE));
#else
     return(ExpressionData(theEnv,execStatus)->SequenceOpMode);
#endif
  }

/********************************************************************
  NAME         : GetFunctionRestrictions
  DESCRIPTION  : Gets DefineFunction2() restriction list for function
  INPUTS       : None
  RETURNS      : A string containing the function restriction codes
  SIDE EFFECTS : EvaluationError set on errors
  NOTES        : None
 ********************************************************************/
globle void *GetFunctionRestrictions(
  void *theEnv,
  EXEC_STATUS)
  {
   DATA_OBJECT temp;
   struct FunctionDefinition *fptr;

   if (EnvArgTypeCheck(theEnv,execStatus,"get-function-restrictions",1,SYMBOL,&temp) == FALSE)
     return((SYMBOL_HN *) EnvAddSymbol(theEnv,execStatus,""));
   fptr = FindFunction(theEnv,execStatus,DOToString(temp));
   if (fptr == NULL)
     {
      CantFindItemErrorMessage(theEnv,execStatus,"function",DOToString(temp));
      SetEvaluationError(theEnv,execStatus,TRUE);
      return((SYMBOL_HN *) EnvAddSymbol(theEnv,execStatus,""));
     }
   if (fptr->restrictions == NULL)
     return((SYMBOL_HN *) EnvAddSymbol(theEnv,execStatus,"0**"));
   return((SYMBOL_HN *) EnvAddSymbol(theEnv,execStatus,fptr->restrictions));
  }

/*************************************************/
/* GetFunctionListFunction: H/L access routine   */
/*   for the get-function-list function.         */
/*************************************************/
globle void GetFunctionListFunction(
  void *theEnv,
  EXEC_STATUS,
  DATA_OBJECT *returnValue)
  {
   struct FunctionDefinition *theFunction;
   struct multifield *theList;
   unsigned long functionCount = 0;

   if (EnvArgCountCheck(theEnv,execStatus,"get-function-list",EXACTLY,0) == -1)
     {
      EnvSetMultifieldErrorValue(theEnv,execStatus,returnValue);
      return;
     }

   for (theFunction = GetFunctionList(theEnv,execStatus);
        theFunction != NULL;
        theFunction = theFunction->next)
     { functionCount++; }

   SetpType(returnValue,MULTIFIELD);
   SetpDOBegin(returnValue,1);
   SetpDOEnd(returnValue,functionCount);
   theList = (struct multifield *) EnvCreateMultifield(theEnv,execStatus,functionCount);
   SetpValue(returnValue,(void *) theList);

   for (theFunction = GetFunctionList(theEnv,execStatus), functionCount = 1;
        theFunction != NULL;
        theFunction = theFunction->next, functionCount++)
     {
      SetMFType(theList,functionCount,SYMBOL);
      SetMFValue(theList,functionCount,theFunction->callFunctionName);
     }
  }

/***************************************/
/* FuncallFunction: H/L access routine */
/*   for the funcall function.         */
/***************************************/
globle void FuncallFunction(
  void *theEnv,
  EXEC_STATUS,
  DATA_OBJECT *returnValue)
  {
   int argCount, i, j;
   DATA_OBJECT theValue;
   FUNCTION_REFERENCE theReference;
   char *name;
   struct multifield *theMultifield;
   struct expr *lastAdd = NULL, *nextAdd, *multiAdd;
   struct FunctionDefinition *theFunction;
    
   /*==================================*/
   /* Set up the default return value. */
   /*==================================*/
   
   SetpType(returnValue,SYMBOL);
   SetpValue(returnValue,EnvFalseSymbol(theEnv,execStatus));
   
   /*=================================================*/
   /* The funcall function has at least one argument: */
   /* the name of the function being called.          */
   /*=================================================*/
   
   if ((argCount = EnvArgCountCheck(theEnv,execStatus,"funcall",AT_LEAST,1)) == -1) return;
   
   /*============================================*/
   /* Get the name of the function to be called. */
   /*============================================*/
   
   if (EnvArgTypeCheck(theEnv,execStatus,"funcall",1,SYMBOL_OR_STRING,&theValue) == FALSE) 
     { return; }
   
   /*====================*/
   /* Find the function. */
   /*====================*/

   name = DOToString(theValue);
   if (! GetFunctionReference(theEnv,execStatus,name,&theReference))
     {
      ExpectedTypeError1(theEnv,execStatus,"funcall",1,"function, deffunction, or generic function name");
      return; 
     }
     
   /*====================================*/
   /* Functions with specialized parsers */
   /* cannot be used with funcall.       */
   /*====================================*/

   if (theReference.type == FCALL)
     {
      theFunction = FindFunction(theEnv,execStatus,name);
      if (theFunction->parser != NULL)
        {
         ExpectedTypeError1(theEnv,execStatus,"funcall",1,"function without specialized parser");
         return; 
        }
     }

   /*======================================*/
   /* Add the arguments to the expression. */
   /*======================================*/
     
   ExpressionInstall(theEnv,execStatus,&theReference);

   for (i = 2; i <= argCount; i++)
     {
      EnvRtnUnknown(theEnv,execStatus,i,&theValue);
      if (GetEvaluationError(theEnv,execStatus))
        {  
         ExpressionDeinstall(theEnv,execStatus,&theReference);
         return; 
        }
      
      switch(GetType(theValue))
        {
         case MULTIFIELD:
           nextAdd = GenConstant(theEnv,execStatus,FCALL,(void *) FindFunction(theEnv,execStatus,"create$"));

           if (lastAdd == NULL)
             { theReference.argList = nextAdd; }
           else
             { lastAdd->nextArg = nextAdd; }
           lastAdd = nextAdd;

           multiAdd = NULL;
           theMultifield = (struct multifield *) GetValue(theValue);
           for (j = GetDOBegin(theValue); j <= GetDOEnd(theValue); j++)
             {
              nextAdd = GenConstant(theEnv,execStatus,GetMFType(theMultifield,j),GetMFValue(theMultifield,j));
              if (multiAdd == NULL)
                { lastAdd->argList = nextAdd; }
              else
                { multiAdd->nextArg = nextAdd; }
              multiAdd = nextAdd;
             }

           ExpressionInstall(theEnv,execStatus,lastAdd);
           break;
         
         default:
           nextAdd = GenConstant(theEnv,execStatus,GetType(theValue),GetValue(theValue));
           if (lastAdd == NULL)
             { theReference.argList = nextAdd; }
           else
             { lastAdd->nextArg = nextAdd; }
           lastAdd = nextAdd;
           ExpressionInstall(theEnv,execStatus,lastAdd);
           break;    
        }
     }

   /*===========================================================*/
   /* Verify a deffunction has the correct number of arguments. */
   /*===========================================================*/

#if DEFFUNCTION_CONSTRUCT
   if (theReference.type == PCALL)
     {
      if (CheckDeffunctionCall(theEnv,execStatus,theReference.value,CountArguments(theReference.argList)) == FALSE)
        {
         PrintErrorID(theEnv,execStatus,"MISCFUN",4,FALSE);
         EnvPrintRouter(theEnv,execStatus,WERROR,"Function funcall called with the wrong number of arguments for deffunction ");
         EnvPrintRouter(theEnv,execStatus,WERROR,EnvGetDeffunctionName(theEnv,execStatus,theReference.value));
         EnvPrintRouter(theEnv,execStatus,WERROR,"\n");
         ExpressionDeinstall(theEnv,execStatus,&theReference);   
         ReturnExpression(theEnv,execStatus,theReference.argList);
         return;
        }
     }
#endif
     
   /*======================*/
   /* Call the expression. */
   /*======================*/
   
   EvaluateExpression(theEnv,execStatus,&theReference,returnValue);
   
   /*========================================*/
   /* Return the expression data structures. */
   /*========================================*/
   
   ExpressionDeinstall(theEnv,execStatus,&theReference);
   ReturnExpression(theEnv,execStatus,theReference.argList);
  }
  
/***********************************/
/* NewFunction: H/L access routine */
/*   for the new function.         */
/***********************************/
globle void NewFunction(
  void *theEnv,
  EXEC_STATUS,
  DATA_OBJECT *returnValue)
  {
   int theType;
   DATA_OBJECT theValue;
   char *name;
    
   /*==================================*/
   /* Set up the default return value. */
   /*==================================*/
   
   SetpType(returnValue,SYMBOL);
   SetpValue(returnValue,EnvFalseSymbol(theEnv,execStatus));
   
   /*================================================================*/
   /* The new function has at least two arguments: the language type */
   /* of the class (e.g. java, .net, c++) and the name of the class. */
   /*================================================================*/
   
   if (EnvArgCountCheck(theEnv,execStatus,"new",AT_LEAST,1) == -1) return;
   
   /*====================================*/
   /* Get the name of the language type. */
   /*====================================*/
   
   if (EnvArgTypeCheck(theEnv,execStatus,"new",1,SYMBOL,&theValue) == FALSE) 
     { return; }
   
   /*=========================*/
   /* Find the language type. */
   /*=========================*/

   name = DOToString(theValue);
   
   theType = FindLanguageType(theEnv,execStatus,name);
   
   if (theType == -1)
     {
      ExpectedTypeError1(theEnv,execStatus,"new",1,"external language");
      return; 
     }

   /*====================================================*/
   /* Invoke the new function for the specific language. */
   /*====================================================*/
   
   if ((EvaluationData(theEnv,execStatus)->ExternalAddressTypes[theType] != NULL) &&
       (EvaluationData(theEnv,execStatus)->ExternalAddressTypes[theType]->newFunction != NULL))
     { (*EvaluationData(theEnv,execStatus)->ExternalAddressTypes[theType]->newFunction)(theEnv,execStatus,returnValue); }
  }
  
/************************************/
/* CallFunction: H/L access routine */
/*   for the new function.          */
/************************************/
globle void CallFunction(
  void *theEnv,
  EXEC_STATUS,
  DATA_OBJECT *returnValue)
  {
   int theType;
   DATA_OBJECT theValue;
   char *name;
   int argumentCount;
   struct externalAddressHashNode *theEA;
    
   /*==================================*/
   /* Set up the default return value. */
   /*==================================*/
   
   SetpType(returnValue,SYMBOL);
   SetpValue(returnValue,EnvFalseSymbol(theEnv,execStatus));
   
   /*=====================================================*/
   /* The call function has at least one argument: either */
   /* an external address or the language type of the     */
   /* method being called (e.g. java, .net, c++).         */
   /*=====================================================*/
   
   if ((argumentCount = EnvArgCountCheck(theEnv,execStatus,"call",AT_LEAST,1)) == -1) return;
      
   /*=========================*/
   /* Get the first argument. */
   /*=========================*/
   
   EnvRtnUnknown(theEnv,execStatus,1,&theValue);

   /*============================================*/
   /* If the first argument is a symbol, then it */
   /* should be an external language type.       */
   /*============================================*/
   
   if (GetType(theValue) == SYMBOL)
     { 
      name = DOToString(theValue);
      
      theType = FindLanguageType(theEnv,execStatus,name);
      
      if (theType == -1)
        { 
         ExpectedTypeError1(theEnv,execStatus,"call",1,"external language symbol or external address");
         return;
        }

      /*====================================================================*/
      /* Invoke the call function for the specific language. Typically this */
      /* will invoke a static method of a class (specified with the third   */
      /* and second arguments to the call function.                         */
      /*====================================================================*/
      
      if ((EvaluationData(theEnv,execStatus)->ExternalAddressTypes[theType] != NULL) &&
          (EvaluationData(theEnv,execStatus)->ExternalAddressTypes[theType]->callFunction != NULL))
        { (*EvaluationData(theEnv,execStatus)->ExternalAddressTypes[theType]->callFunction)(theEnv,execStatus,&theValue,returnValue); }
        
      return;
     }

   /*===============================================*/
   /* If the first argument is an external address, */
   /* then we can determine the external language   */
   /* type be examining the pointer.                */
   /*===============================================*/
   
   if (GetType(theValue) == EXTERNAL_ADDRESS)
     { 
      theEA = (struct externalAddressHashNode *) GetValue(theValue);
      
      theType = theEA->type;
      
      if ((EvaluationData(theEnv,execStatus)->ExternalAddressTypes[theType] != NULL) &&
          (EvaluationData(theEnv,execStatus)->ExternalAddressTypes[theType]->callFunction != NULL))
        { (*EvaluationData(theEnv,execStatus)->ExternalAddressTypes[theType]->callFunction)(theEnv,execStatus,&theValue,returnValue); }
        
      return;
     }
     
   ExpectedTypeError1(theEnv,execStatus,"call",1,"external language symbol or external address");
  }

/************************************/
/* FindLanguageType:    */
/************************************/
static int FindLanguageType(
  void *theEnv,
  EXEC_STATUS,
  char *languageName)
  {
   int theType;
   
   for (theType = 0; theType < EvaluationData(theEnv,execStatus)->numberOfAddressTypes; theType++)
     {
      if (strcmp(EvaluationData(theEnv,execStatus)->ExternalAddressTypes[theType]->name,languageName) == 0)
        { return(theType); }
     }
     
   return -1;
  }
     
/************************************/
/* TimeFunction: H/L access routine */
/*   for the time function.         */
/************************************/
globle double TimeFunction(
  void *theEnv,
  EXEC_STATUS)
  {
   /*=========================================*/
   /* The time function accepts no arguments. */
   /*=========================================*/

   EnvArgCountCheck(theEnv,execStatus,"time",EXACTLY,0);

   /*==================*/
   /* Return the time. */
   /*==================*/

   return(gentime());
  }

/***************************************/
/* TimerFunction: H/L access routine   */
/*   for the timer function.           */
/***************************************/
globle double TimerFunction(
  void *theEnv,
  EXEC_STATUS)
  {
   int numa, i;
   double startTime;
   DATA_OBJECT returnValue;

   startTime = gentime();
   
   numa = EnvRtnArgCount(theEnv,execStatus);

   i = 1;
   while ((i <= numa) && (GetHaltExecution(theEnv,execStatus) != TRUE))
     {
      EnvRtnUnknown(theEnv,execStatus,i,&returnValue);
      i++;
     }

   return(gentime() - startTime);
  }
